package com.aldobucchi.mouse
{
	import com.aldobucchi.core.dependency.DependencySpec;
	import com.aldobucchi.x.flash.events.EventListenerSpec;
	
	import flash.events.Event;
	import flash.events.IEventDispatcher;
	import flash.events.MouseEvent;
	import flash.geom.Point;
	
	import mx.effects.Zoom;
	import mx.events.EffectEvent;


	/**
	 * 
	 * A drop in component that tries to encapsulate the most common use cases
	 * for mouse-wheel based zooming
	 * 
	 * Only works for regular zooming ( where scaleX and Y are always the same )
	 * 
	 * @author aldo.bucchi@gmail.com
	 * 
	 */
	public class MouseWheelZoomer extends MouseTrackerBase
	{


		override protected function getTargetEventListenerSpecs( ):Array
		{
			var els:Array = super.getTargetEventListenerSpecs( );
			
			els.push( 
				new EventListenerSpec( MouseEvent.MOUSE_WHEEL, target_mouseWheel, false, 0, true )	
			);
			
			return els;
		}

		
		///////////////////////////////////////
		// target
		///////////////////////////////////////
		
//		private var targetELS:Array = [
//				new EventListenerSpec( MouseEvent.MOUSE_WHEEL, target_mouseWheel, false, 0, true )	
//			];
//		
//		private var targetSpec:DependencySpec = new DependencySpec( "target", "targetChanged", targetELS );
//		
//		[Bindable("targetChanged")]
//		public function get target( ):UIComponent
//		{
//			return dh.getDependencyValue( targetSpec );
//		}
//
//		public function set target( v:UIComponent ):void
//		{
//			dh.setDependencyValue( targetSpec, v );
//		}
		
		
		
		///////////////////////////////////////
		// dispatcher
		///////////////////////////////////////
		
		private var dispatcherELS:Array = [
				new EventListenerSpec( MouseEvent.MOUSE_WHEEL, dispatcher_mouseWheel, false, 0, true )	
			];
		
		private var dispatcherSpec:DependencySpec = new DependencySpec( "dispatcher", "dispatcherChanged", dispatcherELS );
		
		[Bindable("dispatcherChanged")]
		/**
		 * 
		 * You can pass an alternative source for the mouse_wheel event.
		 * If you leave this property null, then "target" will be monitored for mouse_wheel events.
		 * 
		 * @return 
		 * 
		 */		
		public function get dispatcher( ):IEventDispatcher
		{
			return dh.getDependencyValue( dispatcherSpec );
		}

		public function set dispatcher( v:IEventDispatcher ):void
		{
			dh.setDependencyValue( dispatcherSpec, v );
		}
		
		
		
		
		
		
//		///////////////////////////////////////
//		// enabled
//		///////////////////////////////////////
//		
//		private var enabledSpec:DependencySpec = new DependencySpec( "enabled", "enabledChanged", null, false, true );
//		
//		[Bindable("enabledChanged")]
//		public function get enabled( ):Boolean
//		{
//			return dh.getDependencyValue( enabledSpec );
//		}
//
//		public function set enabled( v:Boolean ):void
//		{
//			dh.setDependencyValue( enabledSpec, v );
//		}




		public var minScale:Number = 0;


		public var maxScale:Number = Number.POSITIVE_INFINITY;
		
		
		
		private var isZoomingSpec:DependencySpec = new DependencySpec( "isZooming", "*" );
		[Bindable("isZoomingChanged")]
		public function get isZooming( ):Boolean
		{
			return dh.getDependencyValue( isZoomingSpec );
		}
		
		private function set_isZooming( v:Boolean ):void
		{
			dh.setDependencyValue( isZoomingSpec, v );
		}
		


		///////////////////////////////////////
		// etc...
		///////////////////////////////////////

		private var zoom:Zoom;

	


		public function MouseWheelZoomer( )
		{
		}
		
		
		
		
		
		private function dispatcher_mouseWheel( event:MouseEvent ):void
		{
			handleMouseWheel( event );
		}
		
		
		
		
		
		private function target_mouseWheel( event:MouseEvent ):void
		{
			if ( dispatcher == null )
				handleMouseWheel( event );
		}
		
		
		private function zoom_effectStart( event:EffectEvent ):void
		{
			// set_isZooming( true );		
		}
		
		
		private function zoom_effectEnd( event:EffectEvent ):void
		{
			set_isZooming( false );			
		}
		
		
		private function handleMouseWheel( event:MouseEvent ):void
		{
		
			if ( ! enabled )
				return;

			event.preventDefault( );

		
			var globalPoint:Point = new Point( event.stageX, event.stageY );
			
			var pointInTarget:Point = target.globalToLocal( globalPoint );
			

			if ( ! zoom )
			{
				zoom = new Zoom( target );
				zoom.addEventListener( EffectEvent.EFFECT_START, zoom_effectStart );
				zoom.addEventListener( EffectEvent.EFFECT_END, zoom_effectEnd );
			}
			
			
			var currentScale:Number = target.scaleX;

			if ( zoom.isPlaying )
			{
				currentScale = zoom.zoomHeightTo;				
			}

			
			// delta: a negative value indicates a downward scroll. Typical values are 1 to 3
			var scaleFactor:Number = Math.abs( event.delta ) / 8 + 1; // TODO: this should be editable
			
			scaleFactor = event.delta > 0 ? scaleFactor : 1 / scaleFactor;				
			
			var newScale:Number = currentScale *= scaleFactor;				
		
		
			if ( newScale < minScale )
				return;
			if ( newScale > maxScale )
				return;


			zoom.zoomHeightTo 	= newScale;				
			zoom.zoomWidthTo 	= newScale;				



			if ( zoom.isPlaying )
			{
				zoom.stop( );
			}

			
			zoom.originX = pointInTarget.x; // TODO: this doesn't work if the target is rotated
			zoom.originY = pointInTarget.y;
		
			zoom.play( );
			set_isZooming( true );	
		
		}
		
		
	}

}